/**
 * This Java Class is part of the Impro-Visor Application
 *
 * Copyright (C) 2005-2011 Robert Keller and Harvey Mudd College
 *
 * Impro-Visor is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Impro-Visor is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * merchantability or fitness for a particular purpose.  See the
 * GNU General Public License for more details.
 *

 * You should have received a copy of the GNU General Public License
 * along with Impro-Visor; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package imp.gui;

import imp.data.NoteSymbol;
import imp.data.PianoKey;

import java.io.StringReader;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.KeyStroke;

import polya.Polylist;
import polya.Tokenizer;

/**
 *
 * @author  Emma Carlson, 2009
 */

public class VoicingKeyboard extends javax.swing.JFrame {

    Notate notate;
    boolean singleNoteMode = false;
    
    /** Creates new form VoicingKeyboard */
    public VoicingKeyboard(Notate notate, int x, int y) {
        initComponents();
        initKeys();
        this.notate = notate;
        setDelegatedKeys();
        setSize(1045, 285);
        setLocation(x, y);
        WindowRegistry.registerWindow(this);
        setVisible(true);       
    }
    
    Notate getNotate()
    {
      return notate;
    }
    
    /**
     * Set additional keys that delegate to the Notate window
     */
    private void setDelegatedKeys()
    {
        // A huge chunk of code, just to have a key stroke do something.
        // In this case, the something is to have control-I open the voicing editor.
        // I tried to accomplish this by adding an accelerator, but everytime
        // I did that in netbeans, it broke the piano key display.
        
        KeyStroke stroke = KeyStroke.getKeyStroke('I', java.awt.event.InputEvent.CTRL_DOWN_MASK);
        jPanel1.getInputMap().put(stroke,  "doSomething");
        jPanel1.getActionMap().put("doSomething",
                            new javax.swing.Action()
              {
              public void actionPerformed(java.awt.event.ActionEvent e) {
                /*getNotate().openVoicingEditor();*/}
              public void addPropertyChangeListener(java.beans.PropertyChangeListener x) {}
              public void removePropertyChangeListener(java.beans.PropertyChangeListener x) {}
              public boolean isEnabled() {return true;}
              public void setEnabled(boolean x) {}
              public void putValue(String y, Object x) {}
              public Object getValue(String y) {return null;}
              }
        );
      
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jPanel1 = new javax.swing.JPanel();
        keyboardLP = new javax.swing.JLayeredPane();
        keyA0 = new javax.swing.JLabel();
        keyB0 = new javax.swing.JLabel();
        keyC1 = new javax.swing.JLabel();
        keyD1 = new javax.swing.JLabel();
        keyE1 = new javax.swing.JLabel();
        keyF1 = new javax.swing.JLabel();
        keyG1 = new javax.swing.JLabel();
        keyA1 = new javax.swing.JLabel();
        keyB1 = new javax.swing.JLabel();
        keyC2 = new javax.swing.JLabel();
        keyD2 = new javax.swing.JLabel();
        keyE2 = new javax.swing.JLabel();
        keyF2 = new javax.swing.JLabel();
        keyG2 = new javax.swing.JLabel();
        keyA2 = new javax.swing.JLabel();
        keyB2 = new javax.swing.JLabel();
        keyC3 = new javax.swing.JLabel();
        keyD3 = new javax.swing.JLabel();
        keyE3 = new javax.swing.JLabel();
        keyF3 = new javax.swing.JLabel();
        keyG3 = new javax.swing.JLabel();
        keyA3 = new javax.swing.JLabel();
        keyB3 = new javax.swing.JLabel();
        keyC4 = new javax.swing.JLabel();
        keyD4 = new javax.swing.JLabel();
        keyE4 = new javax.swing.JLabel();
        keyF4 = new javax.swing.JLabel();
        keyG4 = new javax.swing.JLabel();
        keyA4 = new javax.swing.JLabel();
        keyB4 = new javax.swing.JLabel();
        keyC5 = new javax.swing.JLabel();
        keyD5 = new javax.swing.JLabel();
        keyE5 = new javax.swing.JLabel();
        keyF5 = new javax.swing.JLabel();
        keyG5 = new javax.swing.JLabel();
        keyA5 = new javax.swing.JLabel();
        keyB5 = new javax.swing.JLabel();
        keyC6 = new javax.swing.JLabel();
        keyD6 = new javax.swing.JLabel();
        keyE6 = new javax.swing.JLabel();
        keyF6 = new javax.swing.JLabel();
        keyG6 = new javax.swing.JLabel();
        keyA6 = new javax.swing.JLabel();
        keyB6 = new javax.swing.JLabel();
        keyC7 = new javax.swing.JLabel();
        keyD7 = new javax.swing.JLabel();
        keyE7 = new javax.swing.JLabel();
        keyF7 = new javax.swing.JLabel();
        keyG7 = new javax.swing.JLabel();
        keyA7 = new javax.swing.JLabel();
        keyB7 = new javax.swing.JLabel();
        keyC8 = new javax.swing.JLabel();
        keyBb0 = new javax.swing.JLabel();
        keyCsharp1 = new javax.swing.JLabel();
        keyEb1 = new javax.swing.JLabel();
        keyFsharp1 = new javax.swing.JLabel();
        keyGsharp1 = new javax.swing.JLabel();
        keyBb1 = new javax.swing.JLabel();
        keyCsharp2 = new javax.swing.JLabel();
        keyEb2 = new javax.swing.JLabel();
        keyFsharp2 = new javax.swing.JLabel();
        keyGsharp2 = new javax.swing.JLabel();
        keyBb2 = new javax.swing.JLabel();
        keyCsharp3 = new javax.swing.JLabel();
        keyEb3 = new javax.swing.JLabel();
        keyFsharp3 = new javax.swing.JLabel();
        keyGsharp3 = new javax.swing.JLabel();
        keyBb3 = new javax.swing.JLabel();
        keyCsharp4 = new javax.swing.JLabel();
        keyEb4 = new javax.swing.JLabel();
        keyFsharp4 = new javax.swing.JLabel();
        keyGsharp4 = new javax.swing.JLabel();
        keyBb4 = new javax.swing.JLabel();
        keyCsharp5 = new javax.swing.JLabel();
        keyEb5 = new javax.swing.JLabel();
        keyFsharp5 = new javax.swing.JLabel();
        keyGsharp5 = new javax.swing.JLabel();
        keyBb5 = new javax.swing.JLabel();
        keyCsharp6 = new javax.swing.JLabel();
        keyEb6 = new javax.swing.JLabel();
        keyFsharp6 = new javax.swing.JLabel();
        keyGsharp6 = new javax.swing.JLabel();
        keyBb6 = new javax.swing.JLabel();
        keyCsharp7 = new javax.swing.JLabel();
        keyEb7 = new javax.swing.JLabel();
        keyFsharp7 = new javax.swing.JLabel();
        keyGsharp7 = new javax.swing.JLabel();
        keyBb7 = new javax.swing.JLabel();
        pointerC4 = new javax.swing.JLabel();
        chordRootNoteLabel = new javax.swing.JLabel();
        ctrlClicktoChangeRootLabel = new javax.swing.JLabel();
        futureChordDisplay = new javax.swing.JLabel();
        pastChordDisplay = new javax.swing.JLabel();
        presentChordDisplay = new javax.swing.JLabel();
        ctrlShiftClickExtLabel = new javax.swing.JLabel();
        playChordButton = new javax.swing.JButton();
        jMenuBar1 = new javax.swing.JMenuBar();
        optionsMenu = new javax.swing.JMenu();
        clearKeyboardMI = new javax.swing.JMenuItem();
        resetChordDisplayMI = new javax.swing.JMenuItem();
        playChordMI = new javax.swing.JMenuItem();
        addToSequenceMI = new javax.swing.JMenuItem();
        voicingModeMenu = new javax.swing.JMenu();
        singleNoteModeMI = new javax.swing.JMenuItem();
        chordModeMI = new javax.swing.JMenuItem();
        voicingTransposeMenu = new javax.swing.JMenu();
        upHalfStepMI = new javax.swing.JMenuItem();
        downHalfStepMI = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JSeparator();
        upOctaveMI = new javax.swing.JMenuItem();
        downOctaveMI = new javax.swing.JMenuItem();
        playbackMenu = new javax.swing.JMenu();
        startPlayMI = new javax.swing.JMenuItem();
        pausePlayMI = new javax.swing.JMenuItem();
        stopPlayMI = new javax.swing.JMenuItem();
        startSelPlayMI = new javax.swing.JMenuItem();
        stopSelPlayMI = new javax.swing.JMenuItem();
        windowMenu = new javax.swing.JMenu();
        closeWindowMI = new javax.swing.JMenuItem();
        cascadeMI = new javax.swing.JMenuItem();
        windowMenuSeparator = new javax.swing.JSeparator();

        setTitle("Keyboard");
        setAlwaysOnTop(true);
        getContentPane().setLayout(new java.awt.GridBagLayout());

        jPanel1.setMaximumSize(new java.awt.Dimension(1045, 150));
        jPanel1.setMinimumSize(new java.awt.Dimension(1045, 150));
        jPanel1.setPreferredSize(new java.awt.Dimension(1045, 150));
        jPanel1.setLayout(new java.awt.GridBagLayout());

        keyboardLP.setMinimumSize(new java.awt.Dimension(1045, 150));
        keyboardLP.setRequestFocusEnabled(false);
        keyboardLP.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                keyboardLPMouseClicked(evt);
            }
        });

        keyA0.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA0.setBounds(0, 0, 20, 120);
        keyboardLP.add(keyA0, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB0.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB0.setBounds(20, 0, 20, 120);
        keyboardLP.add(keyB0, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC1.setBounds(40, 0, 20, 120);
        keyboardLP.add(keyC1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyD1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyD1.setBounds(60, 0, 20, 120);
        keyboardLP.add(keyD1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyE1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyE1.setBounds(80, 0, 20, 120);
        keyboardLP.add(keyE1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyF1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyF1.setBounds(100, 0, 20, 120);
        keyboardLP.add(keyF1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyG1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyG1.setBounds(120, 0, 20, 120);
        keyboardLP.add(keyG1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyA1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA1.setBounds(140, 0, 20, 120);
        keyboardLP.add(keyA1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB1.setBounds(160, 0, 20, 120);
        keyboardLP.add(keyB1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC2.setBounds(180, 0, 20, 120);
        keyboardLP.add(keyC2, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyD2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyD2.setBounds(200, 0, 20, 120);
        keyboardLP.add(keyD2, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyE2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyE2.setBounds(220, 0, 20, 120);
        keyboardLP.add(keyE2, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyF2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyF2.setBounds(240, 0, 20, 120);
        keyboardLP.add(keyF2, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyG2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyG2.setBounds(260, 0, 20, 120);
        keyboardLP.add(keyG2, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyA2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA2.setBounds(280, 0, 20, 120);
        keyboardLP.add(keyA2, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB2.setBounds(300, 0, 20, 120);
        keyboardLP.add(keyB2, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC3.setBounds(320, 0, 20, 120);
        keyboardLP.add(keyC3, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyD3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyD3.setBounds(340, 0, 20, 120);
        keyboardLP.add(keyD3, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyE3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyE3.setBounds(360, 0, 20, 120);
        keyboardLP.add(keyE3, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyF3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyF3.setBounds(380, 0, 20, 120);
        keyboardLP.add(keyF3, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyG3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyG3.setBounds(400, 0, 20, 120);
        keyboardLP.add(keyG3, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyA3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA3.setBounds(420, 0, 20, 120);
        keyboardLP.add(keyA3, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB3.setBounds(440, 0, 20, 120);
        keyboardLP.add(keyB3, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC4.setBounds(460, 0, 20, 120);
        keyboardLP.add(keyC4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyD4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyD4.setBounds(480, 0, 20, 120);
        keyboardLP.add(keyD4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyE4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyE4.setBounds(500, 0, 20, 120);
        keyboardLP.add(keyE4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyF4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyF4.setBounds(520, 0, 20, 120);
        keyboardLP.add(keyF4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyG4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyG4.setBounds(540, 0, 20, 120);
        keyboardLP.add(keyG4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyA4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA4.setBounds(560, 0, 20, 120);
        keyboardLP.add(keyA4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB4.setBounds(580, 0, 20, 120);
        keyboardLP.add(keyB4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC5.setBounds(600, 0, 20, 120);
        keyboardLP.add(keyC5, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyD5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyD5.setBounds(620, 0, 20, 120);
        keyboardLP.add(keyD5, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyE5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyE5.setBounds(640, 0, 20, 120);
        keyboardLP.add(keyE5, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyF5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyF5.setBounds(660, 0, 20, 120);
        keyboardLP.add(keyF5, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyG5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyG5.setBounds(680, 0, 20, 120);
        keyboardLP.add(keyG5, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyA5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA5.setBounds(700, 0, 20, 120);
        keyboardLP.add(keyA5, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB5.setBounds(720, 0, 20, 120);
        keyboardLP.add(keyB5, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC6.setBounds(740, 0, 20, 120);
        keyboardLP.add(keyC6, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyD6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyD6.setBounds(760, 0, 20, 120);
        keyboardLP.add(keyD6, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyE6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyE6.setBounds(780, 0, 20, 120);
        keyboardLP.add(keyE6, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyF6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyF6.setBounds(800, 0, 20, 120);
        keyboardLP.add(keyF6, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyG6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyG6.setBounds(820, 0, 20, 120);
        keyboardLP.add(keyG6, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyA6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA6.setBounds(840, 0, 20, 120);
        keyboardLP.add(keyA6, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB6.setBounds(860, 0, 20, 120);
        keyboardLP.add(keyB6, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC7.setBounds(880, 0, 20, 120);
        keyboardLP.add(keyC7, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyD7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyD7.setBounds(900, 0, 20, 120);
        keyboardLP.add(keyD7, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyE7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyE7.setBounds(920, 0, 20, 120);
        keyboardLP.add(keyE7, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyF7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyF7.setBounds(940, 0, 20, 120);
        keyboardLP.add(keyF7, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyG7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyG7.setBounds(960, 0, 20, 120);
        keyboardLP.add(keyG7, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyA7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyA7.setBounds(980, 0, 20, 120);
        keyboardLP.add(keyA7, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyB7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyB7.setBounds(1000, 0, 20, 120);
        keyboardLP.add(keyB7, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyC8.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"))); // NOI18N
        keyC8.setBounds(1020, 0, 20, 120);
        keyboardLP.add(keyC8, javax.swing.JLayeredPane.DEFAULT_LAYER);

        keyBb0.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb0.setBounds(13, 0, 14, 80);
        keyboardLP.add(keyBb0, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyCsharp1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyCsharp1.setBounds(53, 0, 14, 80);
        keyboardLP.add(keyCsharp1, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyEb1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyEb1.setBounds(73, 0, 14, 80);
        keyboardLP.add(keyEb1, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyFsharp1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyFsharp1.setBounds(113, 0, 14, 80);
        keyboardLP.add(keyFsharp1, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyGsharp1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyGsharp1.setBounds(133, 0, 14, 80);
        keyboardLP.add(keyGsharp1, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyBb1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb1.setBounds(153, 0, 14, 80);
        keyboardLP.add(keyBb1, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyCsharp2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyCsharp2.setBounds(193, 0, 14, 80);
        keyboardLP.add(keyCsharp2, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyEb2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyEb2.setBounds(213, 0, 14, 80);
        keyboardLP.add(keyEb2, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyFsharp2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyFsharp2.setBounds(253, 0, 14, 80);
        keyboardLP.add(keyFsharp2, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyGsharp2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyGsharp2.setBounds(273, 0, 14, 80);
        keyboardLP.add(keyGsharp2, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyBb2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb2.setBounds(293, 0, 14, 80);
        keyboardLP.add(keyBb2, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyCsharp3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyCsharp3.setBounds(333, 0, 14, 80);
        keyboardLP.add(keyCsharp3, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyEb3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyEb3.setBounds(353, 0, 14, 80);
        keyboardLP.add(keyEb3, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyFsharp3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyFsharp3.setBounds(393, 0, 14, 80);
        keyboardLP.add(keyFsharp3, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyGsharp3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyGsharp3.setBounds(413, 0, 14, 80);
        keyboardLP.add(keyGsharp3, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyBb3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb3.setBounds(433, 0, 14, 80);
        keyboardLP.add(keyBb3, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyCsharp4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyCsharp4.setBounds(473, 0, 14, 80);
        keyboardLP.add(keyCsharp4, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyEb4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyEb4.setBounds(493, 0, 14, 80);
        keyboardLP.add(keyEb4, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyFsharp4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyFsharp4.setBounds(533, 0, 14, 80);
        keyboardLP.add(keyFsharp4, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyGsharp4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyGsharp4.setBounds(553, 0, 14, 80);
        keyboardLP.add(keyGsharp4, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyBb4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb4.setBounds(573, 0, 14, 80);
        keyboardLP.add(keyBb4, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyCsharp5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyCsharp5.setBounds(613, 0, 14, 80);
        keyboardLP.add(keyCsharp5, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyEb5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyEb5.setBounds(633, 0, 14, 80);
        keyboardLP.add(keyEb5, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyFsharp5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyFsharp5.setBounds(673, 0, 14, 80);
        keyboardLP.add(keyFsharp5, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyGsharp5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyGsharp5.setBounds(693, 0, 14, 80);
        keyboardLP.add(keyGsharp5, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyBb5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb5.setBounds(713, 0, 14, 80);
        keyboardLP.add(keyBb5, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyCsharp6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyCsharp6.setBounds(753, 0, 14, 80);
        keyboardLP.add(keyCsharp6, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyEb6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyEb6.setBounds(773, 0, 14, 80);
        keyboardLP.add(keyEb6, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyFsharp6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyFsharp6.setBounds(813, 0, 14, 80);
        keyboardLP.add(keyFsharp6, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyGsharp6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyGsharp6.setBounds(833, 0, 14, 80);
        keyboardLP.add(keyGsharp6, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyBb6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb6.setBounds(853, 0, 14, 80);
        keyboardLP.add(keyBb6, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyCsharp7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyCsharp7.setBounds(893, 0, 14, 80);
        keyboardLP.add(keyCsharp7, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyEb7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyEb7.setBounds(913, 0, 14, 80);
        keyboardLP.add(keyEb7, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyFsharp7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyFsharp7.setBounds(953, 0, 14, 80);
        keyboardLP.add(keyFsharp7, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyGsharp7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyGsharp7.setBounds(973, 0, 14, 80);
        keyboardLP.add(keyGsharp7, javax.swing.JLayeredPane.PALETTE_LAYER);

        keyBb7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"))); // NOI18N
        keyBb7.setBounds(993, 0, 14, 80);
        keyboardLP.add(keyBb7, javax.swing.JLayeredPane.PALETTE_LAYER);

        pointerC4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/pointer.png"))); // NOI18N
        pointerC4.setBounds(460, 120, 19, 30);
        keyboardLP.add(pointerC4, javax.swing.JLayeredPane.DEFAULT_LAYER);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.ipadx = 1045;
        gridBagConstraints.ipady = 150;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
        jPanel1.add(keyboardLP, gridBagConstraints);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        getContentPane().add(jPanel1, gridBagConstraints);

        chordRootNoteLabel.setText("Bass note indicated in blue.");
        chordRootNoteLabel.setMaximumSize(new java.awt.Dimension(400, 14));
        chordRootNoteLabel.setMinimumSize(new java.awt.Dimension(400, 14));
        chordRootNoteLabel.setPreferredSize(new java.awt.Dimension(400, 14));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        getContentPane().add(chordRootNoteLabel, gridBagConstraints);

        ctrlClicktoChangeRootLabel.setText("Ctrl-click to change bass note, Shift-click to change bass range.");
        ctrlClicktoChangeRootLabel.setMaximumSize(new java.awt.Dimension(450, 14));
        ctrlClicktoChangeRootLabel.setMinimumSize(new java.awt.Dimension(450, 14));
        ctrlClicktoChangeRootLabel.setPreferredSize(new java.awt.Dimension(450, 14));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        getContentPane().add(ctrlClicktoChangeRootLabel, gridBagConstraints);

        futureChordDisplay.setFont(new java.awt.Font("Arial", 1, 14));
        futureChordDisplay.setForeground(new java.awt.Color(51, 153, 255));
        futureChordDisplay.setMaximumSize(new java.awt.Dimension(485, 20));
        futureChordDisplay.setMinimumSize(new java.awt.Dimension(485, 20));
        futureChordDisplay.setPreferredSize(new java.awt.Dimension(485, 20));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        getContentPane().add(futureChordDisplay, gridBagConstraints);

        pastChordDisplay.setFont(new java.awt.Font("Arial", 1, 14));
        pastChordDisplay.setForeground(new java.awt.Color(153, 153, 153));
        pastChordDisplay.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        pastChordDisplay.setMaximumSize(new java.awt.Dimension(375, 20));
        pastChordDisplay.setMinimumSize(new java.awt.Dimension(375, 20));
        pastChordDisplay.setPreferredSize(new java.awt.Dimension(375, 20));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        getContentPane().add(pastChordDisplay, gridBagConstraints);

        presentChordDisplay.setFont(new java.awt.Font("Arial", 1, 18));
        presentChordDisplay.setForeground(new java.awt.Color(0, 153, 0));
        presentChordDisplay.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        presentChordDisplay.setMaximumSize(new java.awt.Dimension(175, 20));
        presentChordDisplay.setMinimumSize(new java.awt.Dimension(175, 20));
        presentChordDisplay.setPreferredSize(new java.awt.Dimension(175, 20));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 110);
        getContentPane().add(presentChordDisplay, gridBagConstraints);

        ctrlShiftClickExtLabel.setText("Ctrl-shift-click to add an extension.");
        ctrlShiftClickExtLabel.setMaximumSize(new java.awt.Dimension(400, 14));
        ctrlShiftClickExtLabel.setMinimumSize(new java.awt.Dimension(400, 14));
        ctrlShiftClickExtLabel.setPreferredSize(new java.awt.Dimension(400, 14));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        getContentPane().add(ctrlShiftClickExtLabel, gridBagConstraints);

        playChordButton.setText("Play Chord");
        playChordButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                playChordButtonActionPerformed(evt);
            }
        });
        playChordButton.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                playChordButtonKeyTyped(evt);
            }
        });
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 50);
        getContentPane().add(playChordButton, gridBagConstraints);

        optionsMenu.setText("Options");

        clearKeyboardMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, 0));
        clearKeyboardMI.setText("Clear Keyboard");
        clearKeyboardMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearKeyboardMIActionPerformed(evt);
            }
        });
        optionsMenu.add(clearKeyboardMI);

        resetChordDisplayMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, 0));
        resetChordDisplayMI.setText("Reset Chord Display");
        resetChordDisplayMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetChordDisplayMIActionPerformed(evt);
            }
        });
        optionsMenu.add(resetChordDisplayMI);

        playChordMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P, 0));
        playChordMI.setText("Play Chord");
        playChordMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                playChordMIActionPerformed(evt);
            }
        });
        optionsMenu.add(playChordMI);

        addToSequenceMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, 0));
        addToSequenceMI.setText("Add to Sequence");
        addToSequenceMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addToSequenceMIActionPerformed(evt);
            }
        });
        optionsMenu.add(addToSequenceMI);

        jMenuBar1.add(optionsMenu);

        voicingModeMenu.setText("Mode");

        singleNoteModeMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_1, 0));
        singleNoteModeMI.setText("Single Note");
        singleNoteModeMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                singleNoteModeMIActionPerformed(evt);
            }
        });
        voicingModeMenu.add(singleNoteModeMI);

        chordModeMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_2, 0));
        chordModeMI.setText("Chords");
        chordModeMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                chordModeMIActionPerformed(evt);
            }
        });
        voicingModeMenu.add(chordModeMI);

        jMenuBar1.add(voicingModeMenu);

        voicingTransposeMenu.setText("Transpose");

        upHalfStepMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_E, 0));
        upHalfStepMI.setBackground(new java.awt.Color(236, 233, 216));
        upHalfStepMI.setText("Up half step");
        upHalfStepMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                upHalfStepMIActionPerformed(evt);
            }
        });
        voicingTransposeMenu.add(upHalfStepMI);

        downHalfStepMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_D, 0));
        downHalfStepMI.setBackground(new java.awt.Color(236, 233, 216));
        downHalfStepMI.setText("Down half step");
        downHalfStepMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                downHalfStepMIActionPerformed(evt);
            }
        });
        voicingTransposeMenu.add(downHalfStepMI);
        voicingTransposeMenu.add(jSeparator1);

        upOctaveMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_T, 0));
        upOctaveMI.setBackground(new java.awt.Color(236, 233, 216));
        upOctaveMI.setText("Up octave");
        upOctaveMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                upOctaveMIActionPerformed(evt);
            }
        });
        voicingTransposeMenu.add(upOctaveMI);

        downOctaveMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, 0));
        downOctaveMI.setBackground(new java.awt.Color(236, 233, 216));
        downOctaveMI.setText("Down octave");
        downOctaveMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                downOctaveMIActionPerformed(evt);
            }
        });
        voicingTransposeMenu.add(downOctaveMI);

        jMenuBar1.add(voicingTransposeMenu);

        playbackMenu.setText("Playback");

        startPlayMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_I, 0));
        startPlayMI.setText("Start play");
        startPlayMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startPlayMIActionPerformed(evt);
            }
        });
        playbackMenu.add(startPlayMI);

        pausePlayMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_L, 0));
        pausePlayMI.setText("Pause play");
        pausePlayMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                pausePlayMIActionPerformed(evt);
            }
        });
        playbackMenu.add(pausePlayMI);

        stopPlayMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_K, 0));
        stopPlayMI.setText("Stop play");
        stopPlayMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopPlayMIActionPerformed(evt);
            }
        });
        playbackMenu.add(stopPlayMI);

        startSelPlayMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, 0));
        startSelPlayMI.setText("Start selection play");
        startSelPlayMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startSelPlayMIActionPerformed(evt);
            }
        });
        playbackMenu.add(startSelPlayMI);

        stopSelPlayMI.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, java.awt.event.InputEvent.SHIFT_MASK));
        stopSelPlayMI.setText("Play from selection to end");
        stopSelPlayMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopSelPlayMIActionPerformed(evt);
            }
        });
        playbackMenu.add(stopSelPlayMI);

        jMenuBar1.add(playbackMenu);

        windowMenu.setMnemonic('W');
        windowMenu.setText("Window");
        windowMenu.addMenuListener(new javax.swing.event.MenuListener() {
            public void menuSelected(javax.swing.event.MenuEvent evt) {
                windowMenuMenuSelected(evt);
            }
            public void menuDeselected(javax.swing.event.MenuEvent evt) {
            }
            public void menuCanceled(javax.swing.event.MenuEvent evt) {
            }
        });

        closeWindowMI.setMnemonic('C');
        closeWindowMI.setText("Close Window");
        closeWindowMI.setToolTipText("Closes the current window (exits program if there are no other windows)");
        closeWindowMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeWindowMIActionPerformed(evt);
            }
        });
        windowMenu.add(closeWindowMI);

        cascadeMI.setMnemonic('A');
        cascadeMI.setText("Cascade Windows");
        cascadeMI.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cascadeMIActionPerformed(evt);
            }
        });
        windowMenu.add(cascadeMI);
        windowMenu.add(windowMenuSeparator);

        jMenuBar1.add(windowMenu);

        setJMenuBar(jMenuBar1);

        pack();
    }// </editor-fold>//GEN-END:initComponents

/**
 * Getting the piano key images.
 */
public javax.swing.ImageIcon whiteKey = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekey.jpg"));

public javax.swing.ImageIcon whiteKeyPressed = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/whitekeypressed.jpg"));

public javax.swing.ImageIcon blackKey = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkey.jpg"));

public javax.swing.ImageIcon blackKeyPressed = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackkeypressed.jpg"));

public javax.swing.ImageIcon bassKey = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/rootkey.JPG"));

public javax.swing.ImageIcon bassKeyPressed = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/rootkeypressed.jpg"));

public javax.swing.ImageIcon blackBassKey = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackrootkey.jpg"));

public javax.swing.ImageIcon blackBassKeyPressed = 
        new javax.swing.ImageIcon(getClass().getResource("/imp/gui/graphics/blackrootkeypressed.jpg"));

/**
 * Setting some useful constants.
 */

public boolean playback = false;    // true if keyboard is in playback mode

public boolean[] currentVoicing = makeValueArray();  

public final int BKHEIGHT = 80;     // height of a black key

public final int BKWIDTH = 14;      // width of a black key

public final int WKWIDTH = 20;      // width of a white key

public final int WKHEIGHT = 120;    // height of a white key

public final int OCTAVE = 140;      // width of an octave

public final int OCTKEYS = 7;       // 7 white keys per octave

public final int P_OCTAVE = 12;     // 12 notes per octave

public final int A = 21;            // MIDI value of 1st key on keyboard

public final int C_EIGHTH = 108;    // MIDI value of last key on keyboard

public final String CTRLCLICK = "Ctrl+Button1";

public final String SHIFTCLICK = "Shift+Button1";

public final String CTRLSHFTCLICK = "Ctrl+Shift+Button1";

public final String SHARP = "#";

public final String FLAT = "b";

public final String ADDTOSEQ = "A";

public final String BACKSPACE = "Backspace";

public final String PLAYCHORD = "P";

public final String EMPTY = "";

public final String UP = "up";

public final String DOWN = "down";


private void keyboardLPMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_keyboardLPMouseClicked

    playback = false;
    
    // Getting the position of the mouse click
    int y = evt.getY();
    int x = evt.getX();
    
    if (y < WKHEIGHT && !playback)
    {
        // True if the user clicked a black key.
        boolean blackPianoKey = false;

        // Determines the key number
        int keyNum = x / WKWIDTH;

        int note = keyNum;

        // gives the octave number (ex. 4 in C4 for middle C) by 
        // determining where x is in relation to the pixel width of an octave
        int octave = ( (x + 5*WKWIDTH) / OCTAVE);

        // Only occurs if the click is at a y position that could be a black key
        if (y < BKHEIGHT) {
            // find the position of the click within the key
            int inKey = x - keyNum*WKWIDTH;

            // if click is in right half of black key
            if (inKey < (BKWIDTH/2 + 1)){
                blackPianoKey = true;
                note -= 1;

                // not on a black key if note number is 1 or 4
                if (note % OCTKEYS == 1 || note % OCTKEYS == 4) {
                    blackPianoKey = false;
                }
            }

            // if click is in left half of black key
            else if (inKey > WKWIDTH - (BKWIDTH/2 + 1)) {
                blackPianoKey = true;
                note = keyNum;

                // not on a black key if note number is 1 or 4
                if (note % OCTKEYS == 1 || note % OCTKEYS == 4) {
                    blackPianoKey = false;
                }
            }
        }

        // determine the MIDI value of the note clicked
        int baseMidi = 0;

        int oct = note - OCTKEYS*(octave - 1);

        if (octave == 0) {
            oct = note - OCTKEYS*octave;
        }

        // if the note is a black key
        if (blackPianoKey)
        {
            switch(oct) {
                case 0:
                    baseMidi = A + 1;     //Bb
                    break;
                case 2:
                    baseMidi = A + 4;     //C#
                    break;
                case 3:
                    baseMidi = A + 6;     //Eb
                    break;
                case 5:
                    baseMidi = A + 9;     //F#
                    break;
                case 6:
                    baseMidi = A + 11;    //G#
                    break;
                case 7:
                    baseMidi = A + 13;    //Bb
                    break;
            }
        }
        // if the note is not a black key
        else
        {
            switch(oct) {
                case 0:
                    baseMidi = A;      //A
                    break;
                case 1:
                    baseMidi = A + 2;  //B
                    break;
                case 2:
                    baseMidi = A + 3;  //C
                    break;
                case 3:
                    baseMidi = A + 5;  //D
                    break;
                case 4:
                    baseMidi = A + 7;  //E
                    break;
                case 5:
                    baseMidi = A + 8;  //F
                    break;
                case 6:
                    baseMidi = A + 10; //G
                    break;
                case 7:
                    baseMidi = A + 12; //A
                    break;
                case 8:
                    baseMidi = A + 14; //B
                    break;
            }
        }

        // Adjust the MIDI value for different octaves
        int midiValue = baseMidi + P_OCTAVE*(octave - 1);

        if (octave == 0) {
            midiValue = baseMidi;
        }
        
        // Pressing the keys and playing the notes
        PianoKey keyPlayed = pianoKeys()[midiValue - A];
        
        int m = evt.getModifiers();
        String mod = evt.getMouseModifiersText(m);
        
        // to change bass note
        if (mod.equals(CTRLCLICK))
        {
            String name = findBassName(midiValue);
            setBass(name, midiValue);
            notate.rebuildVoicingTable();
            return;
        }
        
        // to add extensions to voicings
        else if (mod.equals(CTRLSHFTCLICK))
        {
            // if the key has been pressed, unpress it.
            if (keyPlayed.isPressed()) 
            {
                keyPlayed.setPressed(false);
                keyPlayed.setAsExtension(false);
            }
            // press the correct key
            else 
            {
                keyPlayed.setPressed(true);
                keyPlayed.setAsExtension(true);
            }
            
            if (singleNoteMode)
            {
                pressSingleKey(keyPlayed);
            }
            else
            {
                pressKey(keyPlayed);
            }
            // display voicing in text field
            setVoicingEntryTFfromKeys();
            String s = notate.voicingEntryTFText();
            String c = notate.getChordRootTFText();
            notate.constructAndPlayChord(c,s);
        }
        
        // to change the bass note range
        else if (mod.equals(SHIFTCLICK))
        {
            String name = keyPlayed.getName();
            String lowRange = notate.bassLowRangeTFText();
            String highRange = notate.bassHighRangeTFText();

            if (!lowRange.equals(EMPTY) && !highRange.equals(EMPTY))
            {
                notate.setBassLowRangeTF(EMPTY);
                notate.setBassHighRangeTF(EMPTY);
                notate.setBassLowRangeTF(name);
            }
            else
            {
                NoteSymbol c = NoteSymbol.makeNoteSymbol(lowRange);
                int midi = c.getMIDI();

                if (midiValue > midi)
                {
                    notate.setBassHighRangeTF(name);
                }
                else
                {
                    notate.setBassLowRangeTF(name);
                    notate.setBassHighRangeTF(lowRange);
                }
                int root = findBass();
                name = findBassName(root);
                setBass(name, root);
                notate.rebuildVoicingTable();
            }
            return;
        }
        
        // if the key is just plain clicked
        else
        {
            // if the key has been pressed, unpress it.
            if (keyPlayed.isPressed()) 
            {
                keyPlayed.setPressed(false);
            }
            // press the correct key
            else 
            {
                keyPlayed.setPressed(true);
            }
            if (singleNoteMode)
            {
                pressSingleKey(keyPlayed);
            }
            else
            {
                pressKey(keyPlayed);
            }

            // display voicing in text field
            setVoicingEntryTFfromKeys();
            String s = notate.voicingEntryTFText();
            String c = notate.getChordRootTFText();
            notate.constructAndPlayChord(c,s);
        }
    }
}//GEN-LAST:event_keyboardLPMouseClicked

/**
 * Finds the highest note in a given voicing
 * 
 * @param midiValues
 * @return the integer MIDI value of the highest note in a voicing
 */
private int highestNote(Polylist midiValues)
{
    int highNote = 0;
    
    for (Polylist L = midiValues; L.nonEmpty(); L = L.rest())
    {
        NoteSymbol n = (NoteSymbol)L.first();
        int midi = n.getMIDI();
        if (midi >= highNote)
        {
            highNote = midi;
        }
    }
    return highNote;
}

/**
 * Finds the lowest note in a given voicing
 * 
 * @param midiValues
 * @return the integer MIDI value of the lowest note in the voicing
 */
private int lowestNote(Polylist midiValues)
{
    int lowNote = C_EIGHTH;
    
    for (Polylist L = midiValues; L.nonEmpty(); L = L.rest())
    {
        NoteSymbol n = (NoteSymbol)L.first();
        int midi = n.getMIDI();
        if (midi <= lowNote)
        {
            lowNote = midi;
        }
    }
    return lowNote;
}

/**
 * Transposes a given voicing up a half step
 * 
 * @param v, a String representing a voicing
 */
public void transposeUpHalfStep(String v)
{
    if (v.equals(EMPTY)){
        return;
    }
    
    String e = notate.extEntryTFText();
    Polylist voicing = notate.voicingToList(v);
    Polylist extension = notate.extensionToList(e);
    
    if (highestNote(voicing) + 1 > C_EIGHTH || highestNote(extension) + 1 > C_EIGHTH)
    {
        return;
    }
    
    clearKeyboard();
    notate.clearVoicingEntryTF();

    for (Polylist L = voicing; L.nonEmpty(); L = L.rest())
    {
        if (extension.nonEmpty())
        {
            NoteSymbol ex = (NoteSymbol)extension.first();
            
            int eMidiValue = ex.getMIDI() + 1;
            PianoKey eNote = pianoKeys()[eMidiValue - A];
            eNote.setPressed(true);
            pressKey(eNote);
            extension = extension.rest();
            notate.addExtEntryTFText(eNote.getName());
        }
        
        NoteSymbol n = (NoteSymbol)L.first();
        
        int vMidiValue = n.getMIDI() + 1;
        PianoKey vNote = pianoKeys()[vMidiValue - A];
        vNote.setPressed(true);
        pressKey(vNote);
        notate.addVoicingEntryTFText(vNote.getName());
    }
    int lowRange = notate.getLowerBound();
    int highRange = C_EIGHTH + 1;
    
    if (notate.bassHighRangeTFText().equals(EMPTY))
    {
        highRange = setBassHighRange(lowRange);
    }
    else
    {
        highRange = notate.getUpperBound();
    }
    
    int r = findBass() + 1;
    if (r < lowRange)
    {
        int midi = r + P_OCTAVE;
        String note = findBassName(midi);
        setBass(note, midi);
    }
    else if (r > highRange)
    {
        int midi = r - P_OCTAVE;
        String note = findBassName(midi);
        setBass(note, midi);
    }
    else 
    {
        String note = findBassName(r);
        setBass(note, r);
    }
    
    v = notate.voicingEntryTFText();
    String c = notate.getChordRootTFText();
    
    transposeRoot(c,lowRange,highRange,UP);
    
    notate.rebuildVoicingTable();
    
    notate.constructAndPlayChord(c,v);
}

/**
 * Transposes the current voicing up a half step.
 * 
 * @param evt
 */
private void upHalfStepMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upHalfStepMIActionPerformed

    String v = notate.voicingEntryTFText();
    transposeUpHalfStep(v);

}//GEN-LAST:event_upHalfStepMIActionPerformed

/**
 * Transposes a given voicing down a half step
 * 
 * @param v, a String representing a voicing
 */
public void transposeDownHalfStep(String v)
{
    if (v.equals(EMPTY)){
        return;
    }
    
    String e = notate.extEntryTFText();
    Polylist voicing = notate.voicingToList(v);
    Polylist extension = notate.extensionToList(e);
    
    if (lowestNote(voicing) - 1 < A || lowestNote(extension) - 1 < A)
    {
        return;
    }
    
    clearKeyboard();
    notate.clearVoicingEntryTF();

    for (Polylist L = voicing; L.nonEmpty(); L = L.rest())
    {
        if (extension.nonEmpty())
        {
            NoteSymbol ex = (NoteSymbol)extension.first();
            
            int eMidiValue = ex.getMIDI() - 1;
            PianoKey eNote = pianoKeys()[eMidiValue - A];
            eNote.setPressed(true);
            pressKey(eNote);
            extension = extension.rest();
            notate.addExtEntryTFText(eNote.getName());
        }
        
        NoteSymbol n = (NoteSymbol)L.first();
        
        int vMidiValue = n.getMIDI() - 1;
        PianoKey vNote = pianoKeys()[vMidiValue - A];
        vNote.setPressed(true);
        pressKey(vNote);
        notate.addVoicingEntryTFText(vNote.getName());
    }
    int lowRange = notate.getLowerBound();
    int highRange = C_EIGHTH + 1;
    
    if (notate.bassHighRangeTFText().equals(EMPTY))
    {
        highRange = setBassHighRange(lowRange);
    }
    else
    {
        highRange = notate.getUpperBound();
    }
    
    int r = findBass() - 1;
    
    if (r < lowRange)
    {
        int midi = r + P_OCTAVE;
        String note = findBassName(midi);
        setBass(note, midi);
    }
    else if (r > highRange)
    {
        int midi = r - P_OCTAVE;
        String note = findBassName(midi);
        setBass(note, midi);
    }
    else 
    {
        String note = findBassName(r);
        setBass(note, r);
    }
    
    
    v = notate.voicingEntryTFText();
    String c = notate.getChordRootTFText();
    
    transposeRoot(c,lowRange,highRange,DOWN);
    
    notate.rebuildVoicingTable();
    
    notate.constructAndPlayChord(c,v);
}

/**
 * Transposes the current voicing down a half step.
 * 
 * @param evt
 */
private void downHalfStepMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downHalfStepMIActionPerformed

    String v = notate.voicingEntryTFText();
    transposeDownHalfStep(v);
}//GEN-LAST:event_downHalfStepMIActionPerformed

/**
 * Transposes a given voicing up an octave
 * 
 * @param v, a String representing a voicing
 */
public void transposeUpOctave(String v)
{
    if (v.equals(EMPTY)){
        return;
    }
    
    String e = notate.extEntryTFText();
    Polylist voicing = notate.voicingToList(v);
    Polylist extension = notate.extensionToList(e);
    
    if (highestNote(voicing) + P_OCTAVE > C_EIGHTH || 
            highestNote(extension) + P_OCTAVE > C_EIGHTH)
    {
        return;
    }
    
    clearKeyboard();
    notate.clearVoicingEntryTF();

    for (Polylist L = voicing; L.nonEmpty(); L = L.rest())
    {
        if (extension.nonEmpty())
        {
            NoteSymbol ex = (NoteSymbol)extension.first();
            
            int eMidiValue = ex.getMIDI() + P_OCTAVE;
            PianoKey eNote = pianoKeys()[eMidiValue - A];
            eNote.setPressed(true);
            pressKey(eNote);
            extension = extension.rest();
            notate.addExtEntryTFText(eNote.getName());
        }
        
        NoteSymbol n = (NoteSymbol)L.first();
        
        int vMidiValue = n.getMIDI() + P_OCTAVE;
        PianoKey vNote = pianoKeys()[vMidiValue - A];
        vNote.setPressed(true);
        pressKey(vNote);
        notate.addVoicingEntryTFText(vNote.getName());
    }
    
    v = notate.voicingEntryTFText();
    String c = notate.getChordRootTFText();
    notate.constructAndPlayChord(c,v);
}

/**
 * Transposes the current voicing up an octave.
 * 
 * @param evt
 */
private void upOctaveMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upOctaveMIActionPerformed

    String v = notate.voicingEntryTFText();
    transposeUpOctave(v);

}//GEN-LAST:event_upOctaveMIActionPerformed

/**
 * Transposes a given voicing down an octave
 * 
 * @param v, a String representing a voicing
 */
public void transposeDownOctave(String v)
{
    if (v.equals(EMPTY)){
        return;
    }
    
    String e = notate.extEntryTFText();
    Polylist voicing = notate.voicingToList(v);
    Polylist extension = notate.extensionToList(e);
    
    if (lowestNote(voicing) - P_OCTAVE < A || lowestNote(extension) - P_OCTAVE < A)
    {
        return;
    }
    
    clearKeyboard();
    notate.clearVoicingEntryTF();

    for (Polylist L = voicing; L.nonEmpty(); L = L.rest())
    {
        if (extension.nonEmpty())
        {
            NoteSymbol ex = (NoteSymbol)extension.first();
            
            int eMidiValue = ex.getMIDI() - P_OCTAVE;
            PianoKey eNote = pianoKeys()[eMidiValue - A];
            eNote.setPressed(true);
            pressKey(eNote);
            extension = extension.rest();
            notate.addExtEntryTFText(eNote.getName());
        }
        
        NoteSymbol n = (NoteSymbol)L.first();
        
        int vMidiValue = n.getMIDI() - P_OCTAVE;
        PianoKey vNote = pianoKeys()[vMidiValue - A];
        vNote.setPressed(true);
        pressKey(vNote);
        notate.addVoicingEntryTFText(vNote.getName());
    }
    
    v = notate.voicingEntryTFText();
    String c = notate.getChordRootTFText();
    notate.constructAndPlayChord(c,v);
}

/**
 * Transposes the current voicing down an octave.
 * 
 * @param evt
 */
private void downOctaveMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downOctaveMIActionPerformed

    String v = notate.voicingEntryTFText();
    transposeDownOctave(v);

}//GEN-LAST:event_downOctaveMIActionPerformed


/**
 * Transposes the chord root based on the chord root text field and the bass range.
 * 
 * @param chordRoot
 * @param lowRange
 * @param highRange
 * @param direction
 */
public void transposeRoot(String chordRoot, int lowRange, int highRange, String direction)
{
    if (notate.rootEqualBassCheckboxChecked())
    {
        return;
    }
    
    int midiValue = C_EIGHTH + 1;
    for (PianoKey pk : pianoKeys())
    {
        String name = pk.getName();
        name = nameToBass(name);
        int midi = pk.getMIDI();
        if (name.equals(chordRoot))
        {
            if (midi >= lowRange && midi <= highRange && midi < midiValue)
            {
                midiValue = midi;
            }
        }
    }
    
    if (direction.equals(UP))
    {
        midiValue += 1;
    }
    else
    {
        midiValue -= 1;
    }
    
    // ?? what if midiValue - A is out of range? It has happened. FIX!!
    
    PianoKey root = pianoKeys()[midiValue - A];
    String rootName = root.getName();
    rootName = nameToBass(rootName);
    
    notate.setChordRootTFText(rootName);
    
}

/**
 * Restores the keyboard to its original state.
 */
public void clearKeyboard()
{
    for (PianoKey pk : pianoKeys()) 
     {
        if (pk.isPressed()) 
        {
            pk.setPressed(false);
            pressKey(pk);
        }
    }
}


/**
 * Creates a boolean array for determining whether two voicings are equal
 * 
 * @return
 */
public static boolean[] makeValueArray()
{
    boolean result[] = new boolean[128];
    for (boolean b : result)
    {
        b = false;
    }
    return result;
}

/**
 * Creates two boolean arrays of voicing v1 and voicing v2 and compares the
 * arrays
 * 
 * @param v1
 * @param v2
 * @return true if v1 = v2, false otherwise
 */
public boolean voicingsAreEqual(String v1, String v2)
{
    boolean[] voicing1 = stringToMIDI(v1);
    boolean[] voicing2 = stringToMIDI(v2);
    
    boolean equal = false;
    int it = 0;
    while (voicing1[it] == voicing2[it])
    {
        equal = true;
        if (it == voicing1.length - 1)
        {
            return equal;
        }
        it++;
    }
    
    equal = false;
    return equal;
}

/**
 * Enters a voicing into a boolean array
 * 
 * @param v
 * @return a boolean array with the indeces of the MIDI values of the entered
 * voicing set to true.
 */
public boolean[] stringToMIDI(String v)
{
    boolean[] result = makeValueArray();
    
    if (v.equals(EMPTY))
    {
        return result;
    }
    
    StringReader voicingReader = new StringReader(v);
    Tokenizer in = new Tokenizer(voicingReader);
    Object o = in.nextSexp();
    //int index = ImproVisor.getCurrentWindow().getCurrentSelectionStart();
    Polylist voicing = (Polylist)o;
    
    while (voicing.nonEmpty())
    {
        NoteSymbol n = NoteSymbol.makeNoteSymbol((String)voicing.first());
        int midi = n.getMIDI();
        
        result[midi] = true;
        
        voicing = voicing.rest();
    }
    
    return result;
}

/**
 * Transposes a String that represents a voicing
 * 
 * @param v, the voicing to be transposed
 * @param direction, either "up" or "down"
 * @return a String, the transposition of v
 */
public String transposeVoicing(String v, String direction)
{
    boolean up = false;
    
    if (direction.equals("up"))
    {
        up = true;
    }
    String e = notate.extEntryTFText();
    Polylist voicing = notate.voicingToList(v);
    Polylist extension = notate.extensionToList(e);
    
    if (up)
    {
        if (highestNote(voicing) + P_OCTAVE > C_EIGHTH ||
                highestNote(extension) + P_OCTAVE > C_EIGHTH)
        {
            return v;
        }
    }
    else
    {
        if (lowestNote(voicing) - P_OCTAVE < A ||
                lowestNote(extension) - P_OCTAVE < A)
        {
            return v;
        }
    }
    Polylist P = new Polylist();
    for (Polylist L = voicing; L.nonEmpty(); L = L.rest())
    {
        NoteSymbol n = (NoteSymbol)L.first();
        int midi = n.getMIDI();
        if (up)
        {
            midi = midi + P_OCTAVE;
        }
        else
        {
            midi = midi - P_OCTAVE;
        }
        PianoKey note = pianoKeys()[midi - A];
        String newNote = note.getName();
        P = P.cons(newNote);
    }
    String newVoicing = P.toString();
    return newVoicing;
    
}

/**
 * From the keyboard, finds the voicing currently displayed
 * 
 * @return a String, the voicing.
 */
public String voicingFromKeyboard()
{
    String text = EMPTY;
    for( PianoKey i : pianoKeys() )
    {
        if( i.isPressed() )
        {
            String s = i.getName();
            if (text.equals(EMPTY))
            {
                text = "(" + s + ")";
            }
            else 
            {
                text = text.replace(')', ' ') + s + ")";
            }
        }
    }
    return text;
}

/**
 * Sets the voicing text field based on what notes have been pressed
 */
public void setVoicingEntryTFfromKeys()
{
  notate.clearVoicingEntryTF();

  for( PianoKey i : pianoKeys() )
  {
    if( i.isPressed() && i.isExtension())
    {
        String s = i.getName();
        notate.addExtEntryTFText(s);
    }
    else if( i.isPressed() && !i.isExtension())
    {
        String s = i.getName();
        notate.addVoicingEntryTFText(s);
    }
  }
}

/**
 * If a voicing is entered in the voicing entry text field, it is displayed
 * on the keyboard.
 */
public void showVoicingOnKeyboard(String v)
{
    clearKeyboard();
    
    String e = notate.extEntryTFText();
    
    Polylist voicing = notate.voicingToList(v);
    Polylist extension = notate.extensionToList(e);
    
    voicing = voicing.append(extension);
    
    while (voicing.nonEmpty()) 
    {
        NoteSymbol n = (NoteSymbol)voicing.first();
        int midiValue = n.getMIDI();
        PianoKey key = pianoKeys()[midiValue - A];
        key.setPressed(true);
        pressKey(key);
        voicing = voicing.rest();
    }
}

/**
 * determines whether the keyboard is in playback mode
 * @return true if the keyboard is playing, false otherwise
 */
public boolean isPlaying()
{
    return playback;
}

/**
 * turns playback mode on or off
 * @param on
 */
public void setPlayback(boolean on)
{
    playback = on;
}

/**
 * Sets the text in the future chord display label.
 * 
 * @param text
 */
public void setFutureChordDisplayText(String text)
{
    futureChordDisplay.setText(text);
}

/**
 * Gets the text displayed in the future chord display
 * 
 * @return a String - the chords displayed above the keyboard.
 */
public String getFutureChordDisplayText()
{
    return futureChordDisplay.getText();
}

/**
 * Sets the text in the past chord display label.
 * 
 * @param text
 */
public void setPastChordDisplayText(String text)
{
 pastChordDisplay.setText(text);
}

/**
 * Gets the text displayed in the past chord display
 * 
 * @return a String - the chords displayed above the keyboard.
 */
public String getPastChordDisplayText()
{
    return pastChordDisplay.getText();
}

/**
 * Sets the text in the present chord display label.
 * 
 * @param text
 */
public void setPresentChordDisplayText(String text)
{
    presentChordDisplay.setText(text);
}

/**
 * Gets the text displayed in the present chord display
 * 
 * @return a String - the chords displayed above the keyboard.
 */
public String getPresentChordDisplayText()
{
    return presentChordDisplay.getText();
}

/**
 * Sets single note mode to be on or off.
 * 
 * @param on
 */
public void setSingleNoteMode(boolean on)
{
    this.singleNoteMode = on;
}

private void singleNoteModeMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_singleNoteModeMIActionPerformed

    setSingleNoteMode(true);
    String voicing = notate.voicingEntryTFText();
    currentVoicing = stringToMIDI(voicing);

}//GEN-LAST:event_singleNoteModeMIActionPerformed

private void chordModeMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chordModeMIActionPerformed

    setSingleNoteMode(false);

}//GEN-LAST:event_chordModeMIActionPerformed

private void clearKeyboardMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearKeyboardMIActionPerformed

    clearKeyboard();
    notate.clearVoicingEntryTF();
    
}//GEN-LAST:event_clearKeyboardMIActionPerformed

private void addToSequenceMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addToSequenceMIActionPerformed

    String v = notate.voicingEntryTFText();
    if (v.equals(EMPTY)){
        return;
    }
    notate.addToVoicingSequence();
    
}//GEN-LAST:event_addToSequenceMIActionPerformed

private void playChordMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playChordMIActionPerformed

    String s = notate.voicingEntryTFText();
    String c = notate.getChordRootTFText();

    notate.constructAndPlayChord(c,s);
    
}//GEN-LAST:event_playChordMIActionPerformed

private void startPlayMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startPlayMIActionPerformed

    playback = true;
    notate.playScore();

}//GEN-LAST:event_startPlayMIActionPerformed

private void stopPlayMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopPlayMIActionPerformed

    playback = false;
    notate.stopPlaying();
    clearKeyboard();
    notate.clearVoicingEntryTF();
    resetChordDisplay();
    
    
}//GEN-LAST:event_stopPlayMIActionPerformed

private void startSelPlayMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startSelPlayMIActionPerformed

    playback = true;
    notate.getCurrentStave().playSelection(false, 0);

}//GEN-LAST:event_startSelPlayMIActionPerformed

private void stopSelPlayMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopSelPlayMIActionPerformed

    playback = false;
    notate.getCurrentStave().playSelection(true, 0);
    
}//GEN-LAST:event_stopSelPlayMIActionPerformed

private void resetChordDisplayMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetChordDisplayMIActionPerformed

    resetChordDisplay();
    
}//GEN-LAST:event_resetChordDisplayMIActionPerformed

private void playChordButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playChordButtonActionPerformed

    String s = notate.voicingEntryTFText();
    String c = notate.getChordRootTFText();

    notate.constructAndPlayChord(c,s);

}//GEN-LAST:event_playChordButtonActionPerformed

private void pausePlayMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pausePlayMIActionPerformed

    if (playback)
    {
        notate.pauseToKeyboard();
    }
    
}//GEN-LAST:event_pausePlayMIActionPerformed

private void closeWindowMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeWindowMIActionPerformed
    
    closeWindow();
}//GEN-LAST:event_closeWindowMIActionPerformed

private void cascadeMIActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cascadeMIActionPerformed
    
    WindowRegistry.cascadeWindows(this);
}//GEN-LAST:event_cascadeMIActionPerformed

private void windowMenuMenuSelected(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_windowMenuMenuSelected
    
    windowMenu.removeAll();
    
    windowMenu.add(closeWindowMI);
    
    windowMenu.add(cascadeMI);
    
    windowMenu.add(windowMenuSeparator);
    
    for(WindowMenuItem w : WindowRegistry.getWindows()) {
        
        windowMenu.add(w.getMI(this));      // these are static, and calling getMI updates the name on them too in case the window title changed
        
    }
    
    windowMenu.repaint();
}//GEN-LAST:event_windowMenuMenuSelected

private void playChordButtonKeyTyped(java.awt.event.KeyEvent evt) {                                         
}                                  

/**
 * clears the chord display labels
 */
public void resetChordDisplay()
{
    pastChordDisplay.setText(EMPTY);
    presentChordDisplay.setText(EMPTY);
    futureChordDisplay.setText(EMPTY);
}

/**
 * Transforms a String of form key name (ex. c#++) into a String including
 * only the note name itself (ex. C#)
 * 
 * @param name, a String, the name of a key
 * @return a String that is the name of just a note
 */
public String nameToBass(String name)
{
    String mod = EMPTY;

    if (name.length() > 1)
    {
        String c = name.substring(1,2);
        if (c.equals(SHARP) || c.equals(FLAT))
        {
            mod = c;
        }
    }
    name = name.substring(0,1);
    name = name.toUpperCase();
    name = name + mod;
    
    return name;
}

/**
 * For use if the user neglects to indicate a high range for the bass. Sets
 * the range at one octave above the specified low range.
 * 
 * @param lowRange
 * @param highRange
 */
public int setBassHighRange(int lowRange)
{
    int highRange = C_EIGHTH + 1;
    highRange = lowRange + 11;
    PianoKey high = pianoKeys()[highRange - A];
    String name = high.getName();
    NoteSymbol c = NoteSymbol.makeNoteSymbol(name);
    highRange = c.getMIDI();
    notate.setBassHighRangeTF(name);
    return highRange;
}

/**
 * Takes a MIDI value and finds the bass name - ex. c#-- becomes C#
 * 
 * @param midiValue
 * @return
 */
public String findBassName(int midiValue)
{
    PianoKey bass = pianoKeys()[midiValue - A];
    for (PianoKey pk : pianoKeys())
    {
        if (pk.isBass())
        {
            pk.setIsBass(false);
            pressKey(pk);
        }
    }
    bass.setIsBass(true);
    
    String name = bass.getName();
    name = nameToBass(name);
    return name;
}

/**
 * Sets the chord root key to a given MIDI value.
 * 
 * @param midiValue
 */
public void setBass(String bassNote, int midiValue)
{
    PianoKey bass = pianoKeys()[midiValue - A];
    
    notate.setBassNoteTFText(bassNote);
    
    if (notate.rootEqualBassCheckboxChecked())
    {
        notate.setChordRootTFText(bassNote);
    }
    
    pressKey(bass);
}

public boolean enharmonic(String s1, String s2)
{
    boolean areEnharmonic = false;
    if (s1.equals("Db") && s2.equals("C#") ||
            s1.equals("C#") && s2.equals("Db"))
    { areEnharmonic = true; }
    
    else if (s1.equals("D#") && s2.equals("Eb") ||
            s1.equals("Eb") && s2.equals("D#"))
    { areEnharmonic = true; }
    
    else if (s1.equals("Gb") && s2.equals("F#") ||
            s1.equals("F#") && s2.equals("Gb"))
    { areEnharmonic = true; }
    
    else if (s1.equals("Ab") && s2.equals("G#") ||
            s1.equals("G#") && s2.equals("Ab"))
    { areEnharmonic = true; }
    
    else if (s1.equals("Bb") && s2.equals("A#") ||
            s1.equals("A#") && s2.equals("Bb"))
    { areEnharmonic = true; }
    
    return areEnharmonic;
}

public String enharmonicNote(String note)
{
    if (note.equals("Db"))
    { note = "C#"; }
    else if (note.equals("C#"))
    { note = "Db"; }
    else if (note.equals("D#"))
    { note = "Eb"; }
    else if (note.equals("Eb"))
    { note = "D#"; }
    else if (note.equals("F#"))
    { note = "Gb"; }
    else if (note.equals("Gb"))
    { note = "F#"; }
    else if (note.equals("G#"))
    { note = "Ab"; }
    else if (note.equals("Ab"))
    { note = "G#"; }
    else if (note.equals("A#"))
    { note = "Bb"; }
    else if (note.equals("Bb"))
    { note = "A#"; }
    
    return note;
    
}

/**
 * Finds the chord root key based on the chord root text field.
 * 
 * @return the integer value of the chord root key.
 */
public int findBass()
{
    String bass = notate.getBassNoteTFText();
        
    bass = bass.toLowerCase();

    String first = bass.charAt(0) + EMPTY;
    first = first.toUpperCase();
    if (bass.length() > 1)
    {
        char mod = bass.charAt(1);
        bass = first + mod;
    }
    else
    {
        bass = first;
    }

    int midiValue = C_EIGHTH + 1;
    int lowRange = notate.getLowerBound();
    int highRange = C_EIGHTH + 1;
        
    if (notate.bassHighRangeTFText().equals(EMPTY))
    {
        highRange = setBassHighRange(lowRange);
    }
    else
    {
        highRange = notate.getUpperBound();
    }

    for (PianoKey pk : pianoKeys())
    {
        String name = pk.getName();

        name = nameToBass(name);

        int midi = pk.getMIDI();
        
        if (name.equals(bass) || enharmonic(name,bass))
        {
            if (midi >= lowRange && midi <= highRange && midi < midiValue)
            {
                midiValue = midi;
            }
        }
    }
    return midiValue;
}

/**
 * Displays the chord root key as blue.
 */  
public void showBass()
{
    int midiValue = findBass();
    String name = findBassName(midiValue);
    setBass(name, midiValue);
}

/**
 * Used if One Note Mode is selected.
 * 
 * @param keyPlayed
 */
public void pressSingleKey(PianoKey keyPlayed)
{
    for (int i= A; i<=C_EIGHTH; i++)
    {
        PianoKey key = pianoKeys()[i-A];
        if(!currentVoicing[i] && key.isPressed())
        {
            key.setPressed(false);
            pressKey(key);
        }
    }
    notate.clearVoicingEntryTF();
    keyPlayed.setPressed(true);
    pressKey(keyPlayed);
}

/**
 * pressKey changes the images of the keys based on whether they have been
 * pressed or not.
 * 
 * @param keyPlayed
 */
public void pressKey(PianoKey keyPlayed)
{
    JLabel label = keyPlayed.getLabel();
    Icon onIcon = keyPlayed.getOnIcon();
    Icon offIcon = keyPlayed.getOffIcon();
    Icon rootIcon = keyPlayed.getBassIcon();
    Icon rootIconOn = keyPlayed.getBassOnIcon();

    if (keyPlayed.isPressed()) 
    {
        if (keyPlayed.isBass()) 
        {
            label.setIcon(rootIconOn);
        }
        else 
        {
            label.setIcon(onIcon);
        }
    }
    else if (!keyPlayed.isPressed()) 
    {
        if (keyPlayed.isBass()) 
        {
            label.setIcon(rootIcon);
        }
        else 
        {
            label.setIcon(offIcon);
        }
    }
forcePaint();
}
    
/**
 * Force painting the window, without waiting for repaint to do it,
 * as repaints may be queued when the calling application sleeps.
 */

private void forcePaint()
  {
  paint(getGraphics());
  }



    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem addToSequenceMI;
    private javax.swing.JMenuItem cascadeMI;
    private javax.swing.JMenuItem chordModeMI;
    private javax.swing.JLabel chordRootNoteLabel;
    private javax.swing.JMenuItem clearKeyboardMI;
    private javax.swing.JMenuItem closeWindowMI;
    private javax.swing.JLabel ctrlClicktoChangeRootLabel;
    private javax.swing.JLabel ctrlShiftClickExtLabel;
    private javax.swing.JMenuItem downHalfStepMI;
    private javax.swing.JMenuItem downOctaveMI;
    private javax.swing.JLabel futureChordDisplay;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JLabel keyA0;
    private javax.swing.JLabel keyA1;
    private javax.swing.JLabel keyA2;
    private javax.swing.JLabel keyA3;
    private javax.swing.JLabel keyA4;
    private javax.swing.JLabel keyA5;
    private javax.swing.JLabel keyA6;
    private javax.swing.JLabel keyA7;
    private javax.swing.JLabel keyB0;
    private javax.swing.JLabel keyB1;
    private javax.swing.JLabel keyB2;
    private javax.swing.JLabel keyB3;
    private javax.swing.JLabel keyB4;
    private javax.swing.JLabel keyB5;
    private javax.swing.JLabel keyB6;
    private javax.swing.JLabel keyB7;
    private javax.swing.JLabel keyBb0;
    private javax.swing.JLabel keyBb1;
    private javax.swing.JLabel keyBb2;
    private javax.swing.JLabel keyBb3;
    private javax.swing.JLabel keyBb4;
    private javax.swing.JLabel keyBb5;
    private javax.swing.JLabel keyBb6;
    private javax.swing.JLabel keyBb7;
    private javax.swing.JLabel keyC1;
    private javax.swing.JLabel keyC2;
    private javax.swing.JLabel keyC3;
    private javax.swing.JLabel keyC4;
    private javax.swing.JLabel keyC5;
    private javax.swing.JLabel keyC6;
    private javax.swing.JLabel keyC7;
    private javax.swing.JLabel keyC8;
    private javax.swing.JLabel keyCsharp1;
    private javax.swing.JLabel keyCsharp2;
    private javax.swing.JLabel keyCsharp3;
    private javax.swing.JLabel keyCsharp4;
    private javax.swing.JLabel keyCsharp5;
    private javax.swing.JLabel keyCsharp6;
    private javax.swing.JLabel keyCsharp7;
    private javax.swing.JLabel keyD1;
    private javax.swing.JLabel keyD2;
    private javax.swing.JLabel keyD3;
    private javax.swing.JLabel keyD4;
    private javax.swing.JLabel keyD5;
    private javax.swing.JLabel keyD6;
    private javax.swing.JLabel keyD7;
    private javax.swing.JLabel keyE1;
    private javax.swing.JLabel keyE2;
    private javax.swing.JLabel keyE3;
    private javax.swing.JLabel keyE4;
    private javax.swing.JLabel keyE5;
    private javax.swing.JLabel keyE6;
    private javax.swing.JLabel keyE7;
    private javax.swing.JLabel keyEb1;
    private javax.swing.JLabel keyEb2;
    private javax.swing.JLabel keyEb3;
    private javax.swing.JLabel keyEb4;
    private javax.swing.JLabel keyEb5;
    private javax.swing.JLabel keyEb6;
    private javax.swing.JLabel keyEb7;
    private javax.swing.JLabel keyF1;
    private javax.swing.JLabel keyF2;
    private javax.swing.JLabel keyF3;
    private javax.swing.JLabel keyF4;
    private javax.swing.JLabel keyF5;
    private javax.swing.JLabel keyF6;
    private javax.swing.JLabel keyF7;
    private javax.swing.JLabel keyFsharp1;
    private javax.swing.JLabel keyFsharp2;
    private javax.swing.JLabel keyFsharp3;
    private javax.swing.JLabel keyFsharp4;
    private javax.swing.JLabel keyFsharp5;
    private javax.swing.JLabel keyFsharp6;
    private javax.swing.JLabel keyFsharp7;
    private javax.swing.JLabel keyG1;
    private javax.swing.JLabel keyG2;
    private javax.swing.JLabel keyG3;
    private javax.swing.JLabel keyG4;
    private javax.swing.JLabel keyG5;
    private javax.swing.JLabel keyG6;
    private javax.swing.JLabel keyG7;
    private javax.swing.JLabel keyGsharp1;
    private javax.swing.JLabel keyGsharp2;
    private javax.swing.JLabel keyGsharp3;
    private javax.swing.JLabel keyGsharp4;
    private javax.swing.JLabel keyGsharp5;
    private javax.swing.JLabel keyGsharp6;
    private javax.swing.JLabel keyGsharp7;
    private javax.swing.JLayeredPane keyboardLP;
    public javax.swing.JMenu optionsMenu;
    private javax.swing.JLabel pastChordDisplay;
    private javax.swing.JMenuItem pausePlayMI;
    private javax.swing.JButton playChordButton;
    private javax.swing.JMenuItem playChordMI;
    private javax.swing.JMenu playbackMenu;
    private javax.swing.JLabel pointerC4;
    private javax.swing.JLabel presentChordDisplay;
    private javax.swing.JMenuItem resetChordDisplayMI;
    private javax.swing.JMenuItem singleNoteModeMI;
    private javax.swing.JMenuItem startPlayMI;
    private javax.swing.JMenuItem startSelPlayMI;
    private javax.swing.JMenuItem stopPlayMI;
    private javax.swing.JMenuItem stopSelPlayMI;
    private javax.swing.JMenuItem upHalfStepMI;
    private javax.swing.JMenuItem upOctaveMI;
    private javax.swing.JMenu voicingModeMenu;
    private javax.swing.JMenu voicingTransposeMenu;
    private javax.swing.JMenu windowMenu;
    private javax.swing.JSeparator windowMenuSeparator;
    // End of variables declaration//GEN-END:variables

/**
 * the array of PianoKeys for this Keyboard
 */
    
public PianoKey[] pkeys;
    
/**
 * Initialize all keys.
 */

private void initKeys()
{
    pkeys = new PianoKey[88];
    // 0th octave keys
    pkeys[0] = new PianoKey(21, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA0);
    pkeys[1] = new PianoKey(22, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb0);
    pkeys[2] = new PianoKey(23, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB0);
    
    // 1st octave keys
    pkeys[3] = new PianoKey(24, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC1);
    pkeys[4] = new PianoKey(25, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyCsharp1);
    pkeys[5] = new PianoKey(26, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyD1);
    pkeys[6] = new PianoKey(27, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyEb1);
    pkeys[7] = new PianoKey(28, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyE1);
    pkeys[8] = new PianoKey(29, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyF1);
    pkeys[9] = new PianoKey(30, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyFsharp1);
    pkeys[10] = new PianoKey(31, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyG1);
    pkeys[11] = new PianoKey(32, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyGsharp1);
    pkeys[12] = new PianoKey(33, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA1);
    pkeys[13] = new PianoKey(34, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb1);
    pkeys[14] = new PianoKey(35, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB1);
    
    // 2nd octave keys
    pkeys[15] = new PianoKey(36, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC2);
    pkeys[16] = new PianoKey(37, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyCsharp2);
    pkeys[17] = new PianoKey(38, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyD2);
    pkeys[18] = new PianoKey(39, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyEb2);
    pkeys[19] = new PianoKey(40, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyE2);
    pkeys[20] = new PianoKey(41, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyF2);
    pkeys[21] = new PianoKey(42, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyFsharp2);
    pkeys[22] = new PianoKey(43, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyG2);
    pkeys[23] = new PianoKey(44, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyGsharp2);
    pkeys[24] = new PianoKey(45, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA2);
    pkeys[25] = new PianoKey(46, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb2);
    pkeys[26] = new PianoKey(47, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB2);
    
    // 3rd octave keys
    pkeys[27] = new PianoKey(48, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC3);
    pkeys[28] = new PianoKey(49, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyCsharp3);
    pkeys[29] = new PianoKey(50, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyD3);
    pkeys[30] = new PianoKey(51, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyEb3);
    pkeys[31] = new PianoKey(52, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyE3);
    pkeys[32] = new PianoKey(53, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyF3);
    pkeys[33] = new PianoKey(54, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyFsharp3);
    pkeys[34] = new PianoKey(55, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyG3);
    pkeys[35] = new PianoKey(56, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyGsharp3);
    pkeys[36] = new PianoKey(57, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA3);
    pkeys[37] = new PianoKey(58, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb3);
    pkeys[38] = new PianoKey(59, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB3);
    
    // 4th octave keys
    pkeys[39] = new PianoKey(60, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC4);
    pkeys[40] = new PianoKey(61, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyCsharp4);
    pkeys[41] = new PianoKey(62, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyD4);
    pkeys[42] = new PianoKey(63, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyEb4);
    pkeys[43] = new PianoKey(64, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyE4);
    pkeys[44] = new PianoKey(65, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyF4);
    pkeys[45] = new PianoKey(66, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyFsharp4);
    pkeys[46] = new PianoKey(67, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyG4);
    pkeys[47] = new PianoKey(68, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyGsharp4);
    pkeys[48] = new PianoKey(69, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA4);
    pkeys[49] = new PianoKey(70, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb4);
    pkeys[50] = new PianoKey(71, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB4);
    
    // 5th octave keys
    pkeys[51] = new PianoKey(72, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC5);
    pkeys[52] = new PianoKey(73, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyCsharp5);
    pkeys[53] = new PianoKey(74, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyD5);
    pkeys[54] = new PianoKey(75, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyEb5);
    pkeys[55] = new PianoKey(76, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyE5);
    pkeys[56] = new PianoKey(77, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyF5);
    pkeys[57] = new PianoKey(78, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyFsharp5);
    pkeys[58] = new PianoKey(79, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyG5);
    pkeys[59] = new PianoKey(80, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyGsharp5);
    pkeys[60] = new PianoKey(81, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA5);
    pkeys[61] = new PianoKey(82, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb5);
    pkeys[62] = new PianoKey(83, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB5);
    
    // 6th octave keys
    pkeys[63] = new PianoKey(84, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC6);
    pkeys[64] = new PianoKey(85, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyCsharp6);
    pkeys[65] = new PianoKey(86, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyD6);
    pkeys[66] = new PianoKey(87, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyEb6);
    pkeys[67] = new PianoKey(88, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyE6);
    pkeys[68] = new PianoKey(89, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyF6);
    pkeys[69] = new PianoKey(90, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyFsharp6);
    pkeys[70] = new PianoKey(91, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyG6);
    pkeys[71] = new PianoKey(92, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyGsharp6);
    pkeys[72] = new PianoKey(93, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA6);
    pkeys[73] = new PianoKey(94, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb6);
    pkeys[74] = new PianoKey(95, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB6);
    
    // 7th octave keys
    pkeys[75] = new PianoKey(96, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC7);
    pkeys[76] = new PianoKey(97, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyCsharp7);
    pkeys[77] = new PianoKey(98, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyD7);
    pkeys[78] = new PianoKey(99, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyEb7);
    pkeys[79] = new PianoKey(100, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyE7);
    pkeys[80] = new PianoKey(101, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyF7);
    pkeys[81] = new PianoKey(102, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyFsharp7);
    pkeys[82] = new PianoKey(103, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyG7);
    pkeys[83] = new PianoKey(104, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyGsharp7);
    pkeys[84] = new PianoKey(105, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyA7);
    pkeys[85] = new PianoKey(106, blackKeyPressed, blackKey, blackBassKey, blackBassKeyPressed, keyBb7);
    pkeys[86] = new PianoKey(107, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyB7);
    
    // 8th octave keys
    pkeys[87] = new PianoKey(108, whiteKeyPressed, whiteKey, bassKey, bassKeyPressed, keyC8);
}

    public PianoKey[] pianoKeys() {
        return pkeys;
    }
    
public void closeWindow()
  {
  setVisible(false);

  WindowRegistry.unregisterWindow(this);
  }    
}
